class Pusher {
  constructor(appKey, options) {
    this.appKey = appKey;
    this.options = options;
    this.socket = null;
    this.eventBindings = {};
    this.subscriptions = [];
    this.connect();
  }

  connect() {
    const wsUrl = `wss://ws-${this.options.cluster}.pusher.com/app/${this.appKey}?protocol=7&client=js&version=7.0&flash=false`;
    this.socket = new WebSocket(wsUrl);

    this.socket.onopen = () => {
      console.log("WebSocket connection established");
      this.reSubscribeAll();
    };

    this.socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (data.event.startsWith('pusher:')) return;
      const { channel, event: eventName, data: eventData } = data;
      if (this.eventBindings[channel] && this.eventBindings[channel][eventName]) {
        this.eventBindings[channel][eventName].forEach(callback => callback(JSON.parse(eventData)));
      }
    };

    this.socket.onclose = () => {
      console.log("WebSocket connection closed. Reconnecting...");
      setTimeout(() => this.connect(), 1000); // Delayed reconnect
    };

    this.socket.onerror = (error) => {
      console.error("WebSocket error", error);
    };
  }

  subscribe(channelName, eventName, callback) {
    if (!this.eventBindings[channelName]) {
      this.eventBindings[channelName] = {};
    }
    if (!this.eventBindings[channelName][eventName]) {
      this.eventBindings[channelName][eventName] = [];
    } else {
      // Prevent duplicate subscriptions
      const isAlreadySubscribed = this.eventBindings[channelName][eventName].includes(callback);
      if (isAlreadySubscribed) {
        return;
      }
    }
    this.eventBindings[channelName][eventName].push(callback);

    // Avoid adding duplicate subscriptions
    const isSubscriptionRecorded = this.subscriptions.some(sub => sub.channelName === channelName && sub.eventName === eventName && sub.callback === callback);
    if (!isSubscriptionRecorded) {
      this.subscriptions.push({channelName, eventName, callback});
    }

    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.subscribeChannel(channelName);
    }
  }

  subscribeChannel(channelName) {
    const msg = JSON.stringify({
      event: 'pusher:subscribe',
      data: {
        channel: channelName
      }
    });
    this.socket.send(msg);
  }

  reSubscribeAll() {
    const uniqueChannels = new Set(this.subscriptions.map(sub => sub.channelName));
    uniqueChannels.forEach(channelName => {
      this.subscribeChannel(channelName);
    });
  }
}

var $pusher = new Pusher('9098d8242564d62ddb13', {cluster: 'mt1'});

// 用法
// $pusher.subscribe('my-channel', 'my-event', data => {
//   console.log('Received my-event on my-channel:', data);
// });
